﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading;

using System.Net;
using System.Net.Sockets;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace RVNetworkLib
{
    public class LanClient : Client
    {
        private UdpClient _udpListener;
        private IPEndPoint _serverEP;


        public LanClient() : base(ClientType.LanGame)
        {
            // Useless filed in lan game
            _userID = 0;
            _roomID = 0;

            
        }

        public override void Teardown()
        {
            if (_udpListener != null)
            {
                _udpListener.Close();
                _udpListener = null;
            }

            _serverEP = null;

            base.Teardown();
        }

        public override ErrorCode Setup(string host, int port)
        {
            base.Setup(host, port);

            _udpListener = new UdpClient();
            _udpListener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            _udpListener.ExclusiveAddressUse = false;
            _udpListener.Client.Bind(new IPEndPoint(IPAddress.Any, NetworkEnv.CLIENT_PORT));

            _serverEP = new IPEndPoint(IPAddress.Parse(host), port);

            return ErrorCode.Success;
        }

        protected override ErrorCode SendPacket(Packet p)
        {
            if (_udpListener == null)
            {
                return ErrorCode.NetworkError;
            }

            byte [] rawData = p.Serialize();

            if (rawData.Length != _udpListener.Send(rawData, rawData.Length, _serverEP))
            {
                return ErrorCode.NetworkError;
            }

            return ErrorCode.Success;
        }

        protected override ErrorCode Recv(ref Packet p)
        {
            IPEndPoint iep = new IPEndPoint(IPAddress.Any, NetworkEnv.CLIENT_PORT);
            byte[] data = _udpListener.Receive(ref iep);
            p = Packet.Deserialize(data);

            System.Diagnostics.Trace.WriteLine("Receive new packet");

            return ErrorCode.Success;
        }

        public ErrorCode LanJoinRoom(string userName)
        {
            // Use LINQ to construct JSon Object
            var jsonString = new
            {
                UserName = userName
            };

            byte[] payload = new UTF8Encoding().GetBytes(JsonConvert.SerializeObject(jsonString));

            Packet p = new Packet()
            {
                Type = PacketType.LJOIN_ROOM,
                UserID = _userID,
                DataLength = (uint)payload.Length,
                Payload = payload
            };

            ErrorCode err = Send(p);
            if (err != ErrorCode.Success)
            {
                return err;
            }

            // Receive Accept or Reject
            err = GetResponse(ref p);
            if (err != ErrorCode.Success)
            {
                return err;
            }

            if (p.Type == PacketType.ACCEPT)
            {
                return ErrorCode.Success;
            }
            else if (p.Type == PacketType.REJECT)
            {
                return ErrorCode.RoomFull;
            }
            else
            {
                return ErrorCode.NetworkError;
            }
        }
    }
}
